/**
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */

package net.sourceforge.pmd.eclipse.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import net.sourceforge.pmd.eclipse.ui.ShapeDescriptor;
import net.sourceforge.pmd.eclipse.ui.ShapePainter;
import net.sourceforge.pmd.eclipse.ui.preferences.br.RuleFieldAccessor;
import net.sourceforge.pmd.eclipse.ui.preferences.br.RuleUtil;

public class UniqueItemsAsShapeBuilder extends AbstractCellPainterBuilder {

    private final int width;
    private final int height;
    private final int hAlignment;
    private final Map<Object, ShapeDescriptor> shapesByItem;

    public UniqueItemsAsShapeBuilder(int theWidth, int theHeight, int horizAlignment,
            Map<Object, ShapeDescriptor> theShapesByItem) {
        width = theWidth;
        height = theHeight;
        hAlignment = horizAlignment;
        shapesByItem = theShapesByItem;
    }

    private List<ShapeDescriptor> getterShapesIn(TreeItem tItem, RuleFieldAccessor getter) {
        Set<Comparable<?>> values = RuleUtil.uniqueItemsIn(tItem.getData(), getter);

        List<ShapeDescriptor> shapes = new ArrayList<>(values.size());
        Iterator<?> iter = values.iterator();
        while (iter.hasNext()) {
            ShapeDescriptor desc = shapesByItem.get(iter.next());
            if (desc != null) {
                shapes.add(desc);
            }

        }
        return shapes;
    }

    @Override
    public void addPainterFor(final Tree tree, final int columnIndex, final RuleFieldAccessor getter,
            Map<Integer, List<Listener>> listenersByEventCode) {

        final int xBoundary = 3;

        Listener paintListener = new Listener() {
            @Override
            public void handleEvent(Event event) {
                final int gap = 2;
                if (event.index != columnIndex) {
                    return;
                }

                List<ShapeDescriptor> shapes = getterShapesIn((TreeItem) event.item, getter);
                if (shapes.isEmpty()) {
                    return;
                }

                GC gc = event.gc;
                int verticalOffset = event.height / 2 - height / 2;

                Color original = gc.getBackground();

                final int cellWidth = widthOf(columnIndex, tree);

                for (int i = 0; i < shapes.size(); i++) {
                    ShapeDescriptor shape = shapes.get(i);
                    Color clr = colorManager().colourFor(shape.rgbColor);
                    gc.setBackground(clr);

                    int xOffset = 0;
                    int step = (width + gap) * i;

                    switch (hAlignment) {
                    case SWT.CENTER:
                        xOffset = cellWidth / 2 - width / 2 - xBoundary + step;
                        break;
                    case SWT.RIGHT:
                        xOffset = cellWidth - width - xBoundary;
                        break;
                    case SWT.LEFT:
                        xOffset = xBoundary + step;
                        break;
                    default:
                        // do nothing
                    }

                    ShapePainter.drawShape(width, height, shape.shape, gc, event.x + xOffset, event.y + verticalOffset,
                            null);
                }

                gc.setBackground(original);
            }

        };

        Listener measureListener = new Listener() {
            @Override
            public void handleEvent(Event event) {
                if (event.index != columnIndex) {
                    return;
                }

                Object item = ((TreeItem) event.item).getData();
                if (item == null) {
                    return;
                }
                Set<Comparable<?>> items = RuleUtil.uniqueItemsIn(item, getter);

                event.width = width + (items.size() * width);
                event.height = height;
            }
        };

        addListener(tree, SWT.PaintItem, paintListener, listenersByEventCode);
        addListener(tree, SWT.MeasureItem, measureListener, listenersByEventCode);
    }
}
